package com.qd.p2p.web.action;

import java.text.MessageFormat;
import java.util.*;

import javax.annotation.Resource;

import com.qdlc.p2p.biz.service.*;
import com.qdlc.p2p.biz.service.activity.ActivityPlanEnum;
import org.apache.log4j.Logger;
import org.apache.struts2.convention.annotation.Action;
import org.apache.struts2.convention.annotation.InterceptorRef;
import org.apache.struts2.convention.annotation.Result;

import com.alibaba.fastjson.JSON;
import com.google.common.primitives.Ints;
import com.opensymphony.xwork2.ModelDriven;
import com.qd.p2p.sina.pay.response.sinaQueryBalanceResponse;
import com.qd.p2p.sina.service.SinaPayService;
import com.qdlc.p2p.biz.borrowworker.BorrowHelper;
import com.qdlc.p2p.biz.processor.event.BorrowValueEvent;
import com.qdlc.p2p.biz.processor.task.collection.TenderTaskProcessor;
import com.qdlc.p2p.biz.web.action.BaseAction;
import com.qdlc.p2p.common.constant.BorrowCategory;
import com.qdlc.p2p.common.constant.BorrowStatus;
import com.qdlc.p2p.common.constant.BorrowStyle;
import com.qdlc.p2p.common.constant.BorrowTimeType;
import com.qdlc.p2p.common.constant.BorrowType;
import com.qdlc.p2p.common.constant.Constant;
import com.qdlc.p2p.common.constant.Global;
import com.qdlc.p2p.common.constant.NotifyUrl;
import com.qdlc.p2p.common.constant.QueueLogCategory;
import com.qdlc.p2p.common.constant.RedValidStatus;
import com.qdlc.p2p.common.constant.UserCacheStatus;
import com.qdlc.p2p.common.constant.UserNature;
import com.qdlc.p2p.common.constant.UserType;
import com.qdlc.p2p.common.core.queue.QueueHandlers;
import com.qdlc.p2p.common.exception.BorrowException;
import com.qdlc.p2p.common.exception.BusinessException;
import com.qdlc.p2p.common.util.BeanUtil;
import com.qdlc.p2p.common.util.BigDecimalUtil;
import com.qdlc.p2p.common.util.DateUtil;
import com.qdlc.p2p.common.util.LogFactory;
import com.qdlc.p2p.common.util.MessageUtil;
import com.qdlc.p2p.common.util.MoneyUtil;
import com.qdlc.p2p.common.util.StringUtil;
import com.qdlc.p2p.common.util.code.MD5;
import com.qdlc.p2p.dal.common.SystemConfigHelper;
import com.qdlc.p2p.dal.common.SystemConfigHelper.Nid;
import com.qdlc.p2p.dal.common.model.jpa.PageDataList;
import com.qdlc.p2p.dal.dao.AccountDao;
import com.qdlc.p2p.dal.dto.Account;
import com.qdlc.p2p.dal.dto.Borrow;
import com.qdlc.p2p.dal.dto.BorrowMortgage;
import com.qdlc.p2p.dal.dto.BorrowRepayment;
import com.qdlc.p2p.dal.dto.BorrowUpload;
import com.qdlc.p2p.dal.dto.QueueLog;
import com.qdlc.p2p.dal.dto.User;
import com.qdlc.p2p.dal.dto.UserBaseInfo;
import com.qdlc.p2p.dal.dto.UserCache;
import com.qdlc.p2p.dal.dto.UserIdentify;
import com.qdlc.p2p.dal.dto.UserUpload;
import com.qdlc.p2p.dal.dto.VerifyLog;
import com.qdlc.p2p.dal.model.AccountModel;
import com.qdlc.p2p.dal.model.AwardModel;
import com.qdlc.p2p.dal.model.BorrowModel;
import com.qdlc.p2p.dal.model.BorrowMortgageModel;
import com.qdlc.p2p.dal.model.BorrowTenderModel;
import com.qdlc.p2p.dal.model.UserBaseInfoModel;
import com.qdlc.p2p.dal.model.UserCacheModel;
import com.qdlc.p2p.dal.model.UserCertificationApplyModel;
import com.qdlc.p2p.dal.model.UserCertificationModel;
import com.qdlc.p2p.dal.model.UserIdentifyModel;
import com.qdlc.p2p.dal.util.UserUtils;

/**
 * 我要投资
 *
 * @author cx
 * @version 2.0
 */
public class InvestAction extends BaseAction<BorrowModel> implements ModelDriven<BorrowModel> {

    private final static Logger logger = LogFactory.TRADE_LOGGER;

    @Resource
    private BorrowService borrowService;

    @Resource
    private UserCertificationService userCertificationService;

    @Resource
    private UserCertificationApplyService userCertificationApplyService;

    @Resource
    private UserIdentifyService userIdentifyService;

    @Resource
    private AccountService accountService;

    @Resource
    private UserUploadService userUploadService;

    @Resource
    private BorrowMortgageService borrowMortgageService;

    @Resource
    private BorrowUploadService borrowUploadService;

    @Resource
    private UserCacheService userCacheService;

    @Resource
    private VerifyLogService verifyLogService;

    @Resource
    private BorrowRepaymentService borrowRepaymentService;

    @Resource
    private UserBaseInfoService userBaseInfoService;

    @Resource
    private ExperienceService experienceService;

    @Resource
    private UserService userService;

    @Resource
    private AwardSearchService awardSearchService;

    @Resource
    private SinaPayService sinaPayService;

    @Resource
    private BorrowTenderService borrowTenderService;

    @Resource
    private  CashAwardRuleService cashAwardRuleService;


    /** 禁止查看状态的标种 */
    private static int[] NO_VIEWS_BORROW = {BorrowStatus.STATUS_TRIAL_PASSED,
            BorrowStatus.STATUS_RECHECK_PASS,
            BorrowStatus.STATUS_RECHECK_PASSLESS,
            BorrowStatus.STATUS_REPAYMENT_START,
            BorrowStatus.STATUS_REPAYMENT_DOING,
            BorrowStatus.STATUS_REPAYMENT_DONE,
            BorrowStatus.STATUS_RECHECK_PASSLESS2,
            BorrowStatus.STATUS_MANAGER_CANCEL2};

    /** 返回给页面的数据集合 */
    private Map retMap;

    private User user;

    /**
     * 我要投资页面
     *
     * @return
     * @throws Exception
     */
    @Action(value = "/invest/index", results = {@Result(name = "index", type = "ftl", location = "/invest/index.html")})
    public String index() throws Exception {
        return "index";
    }

    /**
     * 我要投资列表页（输出json字符串）
     *
     * @throws Exception if has error
     */
    @SuppressWarnings("static-access")
    @Action("/invest/investJson")
    public void investJson() throws Exception {
        retMap = new HashMap<String, Object>();
        Borrow borrow = BorrowHelper.getWorker(model).prototype();
        model = model.instanceCurr(borrow, model);
        model.setScales(101); // 标记为不显示用户信息
        PageDataList<BorrowModel> list = borrowService.getList(model);
        retMap.put("data", list);
        retMap.put("nowTime", DateUtil.getNow());
        user = getSessionUser();
        printWebJson(getStringOfJpaObj(retMap));
    }

    /**
     * 趣影计划投资列表页（输出json字符串）
     *
     * @throws Exception if has error
     */
    @SuppressWarnings("static-access")
    @Action("/invest/filmInvestJson")
    public void filmInvestJson() throws Exception {
        retMap = new HashMap<String, Object>();
        Borrow borrow = BorrowHelper.getWorker(model).prototype();
        model = model.instanceCurr(borrow, model);
        model.setScales(101); // 标记为不显示用户信息
        PageDataList<BorrowModel> list = borrowService.getList(model);

        if (list.getList().size() > 0) {
            for (int i = 0; i < list.getList().size(); i++) {
                list.getList().get(i).setPicurl(borrowUploadService.findPicByBorrowIdAndType(list.getList().get(i).getId()).get(0).getPicPath());
            }
        }

        retMap.put("data", list);
        retMap.put("nowTime", DateUtil.getNow());
        retMap.put("url", SystemConfigHelper.getValue(Nid.IMAGE_SERVER_URL));
        user = getSessionUser();
        printWebJson(getStringOfJpaObj(retMap));
    }

    /**
     * 标详情页面
     *
     * @return String
     * @throws Exception
     */
    @Action(value = "/invest/detail", interceptorRefs = @InterceptorRef("globalStack"))
    public String detail() throws Exception {
        String uuid = paramString("uuid");
        Borrow borrow = borrowService.find(uuid);
        if (borrow == null) {
            throw new BorrowException("当前借款标不存在");
        }
        String borrowPreview = paramString("borrowPreview");
        if (borrowPreview == null && getSessionUserId() != borrow.getUser().getUserId()) {
            if (borrow.getStatus() != 1 && borrow.getStatus() != 3
                    && borrow.getStatus() != 4 && borrow.getStatus() != 49
                    && borrow.getStatus() != 6 && borrow.getStatus() != 7
                    && borrow.getStatus() != 8 && borrow.getStatus() != 59) {
                throw new BorrowException("此借款标已撤回或审核不通过，无法查看！");
            }
        }
        request.setAttribute("borrowPreview", borrowPreview);
        request.setAttribute("uuid", uuid);
        request.setAttribute("redPacketsRule", SystemConfigHelper.getValue(Nid.RED_PACKETS_RULE));// 投标使用红包规则

        if (borrow.getType() == BorrowType.TYPE_MORTGAGE) {
            return "103detail";
        } else {
            return "detail";
        }
    }

    /**
     * 标详情页面
     *
     * @return String
     * @throws Exception
     */
    @Action(value = "/invest/103detail", interceptorRefs = @InterceptorRef("globalStack"))
    public String filmInvestDetail() throws Exception {
        String uuid = paramString("uuid");
        Borrow borrow = borrowService.find(uuid);
        if (borrow == null) {
            throw new BorrowException("当前借款标不存在");
        }
        String borrowPreview = paramString("borrowPreview");
        if (borrowPreview == null && getSessionUserId() != borrow.getUser().getUserId()) {
            if (!Ints.contains(NO_VIEWS_BORROW, borrow.getStatus())) {
                throw new BorrowException("此借款标已撤回或审核不通过，无法查看！");
            }
        }

        request.setAttribute("borrowPreview", borrowPreview);
        request.setAttribute("uuid", uuid);

        if (borrow.getType() == BorrowType.TYPE_MORTGAGE) {
            return "103detail";
        } else {
            return "detail";
        }
    }

    /**
     * 标详情JSON数据
     *
     * @throws Exception
     */
    @Action(value = "/invest/borrowDetail", interceptorRefs = @InterceptorRef("globalStack"))
    public void borrowDetail() throws Exception {
        saveToken("tenderToken");
        retMap = new HashMap<String, Object>();

        String tenderToken = (String) session.get("tenderToken");
        user = getSessionUser();

        String uuid = paramString("uuid");
        Borrow bw = borrowService.find(uuid);
        long borrowId = bw.getId();
        List<BorrowUpload> borrowUploads = borrowUploadService.findByBorrowId(borrowId);
        retMap.put("borrowUploads", borrowUploads);
        Borrow b = borrowService.findNotFlow(borrowId);

        List<UserUpload> userUploadlist = userUploadService.findByUser(b.getUser());
        retMap.put("userUploadlist", userUploadlist);
        UserCache borrowUserCache = userCacheService.findByUserId(b.getUser().getUserId());
        UserCacheModel uc = UserCacheModel.instance(borrowUserCache);
        String companyName = uc.getCompanyName();
        if (companyName != null && companyName.length() > 5) {
            uc.setCompanyName(companyName.substring(0, 2) + "****" + companyName.substring(companyName.length() - 4));
        }
        retMap.put("uc", uc);
        retMap.put("size", borrowUploadService.findByBorrowIdAndType(borrowId).size());
        double interest = BigDecimalUtil.mul(b.getApr(), b.getTimeLimit()) * 100 / 30;
        PageDataList<BorrowTenderModel> list = borrowTenderService.list(b.getId(), this.model.getPage(), 0);
        BorrowModel borrow = BorrowModel.instance(b);
        VerifyLog log = verifyLogService.findByType(borrow.getId(), "borrow", 1);
        if (log != null) {
            borrow.setStartTime(DateUtil.dateStr2(log.getTime()));
        }
        String username = borrow.getUser().getUserName();
        String hideName = username.charAt(0) + "******" + username.charAt(username.length() - 1);
        borrow.setUserName(hideName);
        borrow.setUser(null);
        retMap.put("isDirectional", !StringUtil.isBlank(borrow.getPwd()));
        borrow.setPwd(null);
        retMap.put("borrow", borrow);
        retMap.put("tenderToken", tenderToken);
        retMap.put("accountWait", BigDecimalUtil.sub(borrow.getAccount(), borrow.getAccountYes()));
        retMap.put("interest", BigDecimalUtil.round(interest));
        retMap.put("data", list);
        retMap.put("url", SystemConfigHelper.getValue(Nid.IMAGE_SERVER_URL));

        /** 未初审  */
        if (borrow.getCategory() == BorrowStatus.STATUS_PUBLISHING) {
            retMap.put("canTender", borrowTenderService.canTenderForCategory(user, 0)); // 判断用户是否允许投资新手标
        } else {
            retMap.put("canTender", Boolean.TRUE);
        }

        // 服务器当前时间，开标倒计时用
        retMap.put("serverNowTime", DateUtil.getNow());

        if (user != null) {
            UserIdentify userIdentify = userIdentifyService.findByUserId(getSessionUserId());
            UserIdentifyModel userIdentifyModel = UserIdentifyModel.instance(userIdentify);
            userIdentifyModel.setUserName(hideName);
            userIdentifyModel.setUser(null);
            retMap.put("userInvestIdentify", userIdentifyModel);
            retMap.put("payPwd", StringUtil.isBlank(user.getPayPwd()));
        }
        if (!"1".equals(paramString("borrowPreview"))) {
            if (!StringUtil.isBlank(user)) {// 防止空指针
                UserCache userCache = UserUtils.getUserCacheByUserId(user.getUserId());
                retMap.put("userType", userCache.getUserType());
                Account account = accountService.findAccountByUserId(user.getUserId());
                AccountModel accountModel = AccountModel.instance(account);
                accountModel.setUser(null);
                retMap.put("account", accountModel);
                retMap.put("isLogin", Boolean.TRUE);
            } else {
                retMap.put("userType", UserType.INVESTOR); // 投资人
                retMap.put("isLogin", Boolean.FALSE);
            }
            retMap.put("borrowPreview", 2);// 代表非后台预览标
        }
        List<UserCertificationApplyModel> certificationApply = userCertificationApplyService.findByUser(b.getUser());
        retMap.put("certificationApply", certificationApply);
        // 借款人信息
        UserBaseInfo userBaseInfo = userBaseInfoService.findByUserId(b.getUser().getUserId());
        if (userBaseInfo != null) {
            UserBaseInfoModel userBaseInfoModel = UserBaseInfoModel.instance(userBaseInfo);
            userBaseInfoModel.setUser(null); // 防止前台查看用户信息
            retMap.put("userBaseInfo", userBaseInfoModel);
        }
        if (borrow.getType() == BorrowType.TYPE_OFFVOUCH&&!borrow.isRecommend()&&(borrow.getStatus() == 3 || borrow.getStatus() == 6 || borrow.getStatus() == 7 || borrow.getStatus() == 8)&&borrow.getCategory()==BorrowCategory.USUALLY) {
            AwardModel firstTender = (AwardModel) context.getAttribute("firstTender" + borrow.getUuid());
            AwardModel lastTender = (AwardModel) context.getAttribute("lastTender" + borrow.getUuid());
            AwardModel mostTender = (AwardModel) context.getAttribute("mostTender" + borrow.getUuid());
            if (StringUtil.isBlank(firstTender) || StringUtil.isBlank(firstTender.getMobile())) {
                firstTender = awardSearchService.firstTender(borrow.getId());
                context.setAttribute("firstTender" + borrow.getUuid(), firstTender);
            }
            if (StringUtil.isBlank(lastTender) || StringUtil.isBlank(lastTender.getMobile())) {
                lastTender = awardSearchService.lastTender(borrow.getId());
                context.setAttribute("lastTender" + borrow.getUuid(), lastTender);
             }
             if (StringUtil.isBlank(mostTender) || StringUtil.isBlank(mostTender.getMobile())) {
                mostTender = awardSearchService.mostTender(borrow.getId());
                context.setAttribute("mostTender" + borrow.getUuid(), mostTender);
             }
                Date reviewTime = borrow.getReviewTime();
                if(reviewTime!=null){
                    cashAwardRuleService.getCashAwardRule(retMap, ActivityPlanEnum.SYNTHETIC_APERTURE.getEnTache(),"firstTender",reviewTime.getTime());
                    if(!(firstTender.getUserId()==lastTender.getUserId()&&firstTender.getUserId()==mostTender.getUserId())) {
                    cashAwardRuleService.getCashAwardRule(retMap, ActivityPlanEnum.BE_ACCOMPLISHED.getEnTache(),"lastTender",reviewTime.getTime());
                    }
                    cashAwardRuleService.getCashAwardRule(retMap, ActivityPlanEnum.GAMBLE_AT_HIGH_STAKES.getEnTache(),"mostTender",reviewTime.getTime());
                }
                retMap.put("firstTender", firstTender);
                retMap.put("lastTender", lastTender);
                retMap.put("mostTender", mostTender);
        }
        printWebJson(getStringOfJpaObj(retMap));
    }

    /**
     * 投标记录详细
     *
     * @return String
     * @throws Exception if has error
     */
    @Action("/invest/detailTenderForJson")
    public String detailTenderForJson() throws Exception {
        long borrowId = paramLong("id");
        PageDataList<BorrowTenderModel> list = borrowTenderService.list(borrowId, model.getPage(), 0);

        retMap = new HashMap<String, Object>();
        retMap.put("data", list);
        printWebJson(getStringOfJpaObj(retMap));
        return null;
    }

    /**
     * 资料审核
     *
     * @return String
     * @throws Exception if has error
     */
    @Action("/invest/detailForAuditInfo")
    public String detailForAuditInfo() throws Exception {
        long userId = paramLong("userId");
        PageDataList<UserCertificationModel> attestationList = userCertificationService.findByUserId(userId, 1, this.model.getPage());
        retMap = new HashMap<String, Object>();
        retMap.put("data", attestationList);
        printWebJson(getStringOfJpaObj(retMap));
        return null;
    }

    /**
     * PS 投标
     *
     * @throws Exception if has error
     */
    @Action(value = "/invest/tender",
            interceptorRefs = {@InterceptorRef("session"), @InterceptorRef("globalStack")}, results =
            {@Result(name = "result", type = "ftl", location = "/member/tpp/" + Constant.TPP_PACKAGE + "/tender.html"),
                    @Result(name = "retResult", type = "ftl", location = "/retresult.html"),
                    @Result(name = "filmRetResult", type = "ftl", location = "/filmRetresult.html"),
                    @Result(name = "main", type = "ftl", location = "/member/main.html"),
                    @Result(name = "main_firm", type = "ftl", location = "/member_borrow/main.html"),
                    @Result(name = "main_vouch", type = "ftl", location = "/member_guarantee/main.html")})
    public String tender() throws Exception {

        // 重复提交校验
        checkToken("tenderToken");

        long userId = getSessionUserId(); // 用户ID
        User tenderUser = userService.find(userId); // 不从Session取 防止Session中用户不是最新的
        UserIdentify userIdentify = userIdentifyService.findByUserId(userId);

        String uuid = paramString("uuid"); // 标ID
        if (StringUtil.isBlank(uuid)) {
            UserCache uc = UserUtils.getUserCacheByUserId(tenderUser);
            // 投资借款人 或 贷款人
            if (uc.getUserType() == UserType.INVESTMENT_BORROWER || uc.getUserType() == UserType.BORROWER) {
                return "main_firm";
                // 担保账户
            } else if (uc.getUserNature() == UserNature.SECURED_ACCOUNT) {
                return "main_vouch";
            }
            return "main";
        }
        Borrow borrow = borrowService.find(uuid);

        BorrowModel borrowModel = BorrowModel.instance(borrow);

        // 设置用户输入的信息
        borrowModel.setMoney(this.model.getMoney());
        borrowModel.setPayPwd(this.model.getPayPwd());
        borrowModel.setInPwd(this.model.getPwd());

        // 校验用户认证状态及用户类型
        model.checkUser(userIdentify, UserUtils.getUserCacheByUserId(tenderUser));

        // 有定向密码则校验定向密码
        if (StringUtil.isNotBlank(borrow.getPwd()) && !model.getPwd().equals(borrow.getPwd())) {
            throw new BorrowException("定向标密码不正确!", BorrowException.TYPE_CLOSE);
        }

        // 生成投标标记
        String resultFlag = System.currentTimeMillis() + "" + Math.random() * 10000;
        borrowModel.setTenderResultFlg(resultFlag);
        switch (borrowModel.getCategory()) {
            case BorrowCategory.EXPERIENCE: // 体验标
                borrowModel.setExperiences(this.model.getExperiences());
                checkTender(borrowModel, tenderUser, true);
                tenderExperience(borrowModel, tenderUser);
                break;
            default:
                checkTender(borrowModel, tenderUser, false);
                tenderCustom(borrowModel, tenderUser);
                break;
        }

        if (borrow.getType() != BorrowType.TYPE_MORTGAGE) {  //判断是否是趣影计划
            request.setAttribute("resultFlag", resultFlag);
            request.setAttribute("left_url", "/invest/" + borrowModel.getUuid() + "/detail.html"); // 成功返回地址
            request.setAttribute("right_url", "/member/main.html"); // 成功返回地址
            request.setAttribute("back_url", "/member/invest/myInvest.html"); // 成功返回地址
            request.setAttribute("left_msg", MessageUtil.getMessage("I10008"));
            request.setAttribute("right_msg", MessageUtil.getMessage("I10001"));
            request.setAttribute("r_msg", MessageUtil.getMessage("I10007"));
            return "retResult";
        } else {
            request.setAttribute("resultFlag", resultFlag);
            request.setAttribute("left_url", "/invest/" + borrowModel.getUuid() + "/103detail.html"); // 成功返回地址
            request.setAttribute("right_url", "/member/redpacket/availableRedEnvelope.html?tab=3"); // 成功返回地址
            request.setAttribute("back_url", "/member/invest/myInvest.html"); // 成功返回地址
            request.setAttribute("left_msg", MessageUtil.getMessage("I10008"));
            request.setAttribute("right_msg", MessageUtil.getMessage("I10021"));
            request.setAttribute("r_msg", MessageUtil.getMessage("I10007"));
            return "filmRetResult";
        }
    }

    /**
     * 投体验标
     */
    private void tenderExperience(BorrowModel borrowModel, User tenderUser) {
        double tenderAmount = experienceService.sumAmount(this.model.getExperiences(), tenderUser.getUserId());
        borrowModel.setMoney(tenderAmount); // 投标金额
        // 投标放入队列中处理
        putQueue(borrowModel, tenderUser);
        request.setAttribute("tender", null);
    }

    /**
     * 投普通标
     */
    private void tenderCustom(BorrowModel borrowModel, User tenderUser) {
        // 封装用户扩展参数
        Map map = new HashMap<String, Object>();
        long[] redIds = this.model.getRedEnvelopeIds();
        map.put("redIds", redIds[0] == 0 ? null : redIds); // 红包IDS
        map.put("type", borrowModel.getType()); // 标的类型
        map.put("uuid", borrowModel.getUuid()); // 标ID
        map.put("tenderUserId", String.valueOf(tenderUser.getUserId())); // 投标用户ID
        map.put("tenderUserName", tenderUser.getUserName()); // 投标用户ID
        map.put("tppUserCustId", UserUtils.getUserTppCustId(tenderUser.getUserId())); // 用户新浪标识ID

        long rateInterestId = this.model.getRateInterestId();
        map.put("rateId", rateInterestId == 0 ? null : rateInterestId); // 加息券ID
        borrowModel.setParam(JSON.toJSONString(map));

        // 投标放入队列中处理
        putQueue(borrowModel, tenderUser);
        request.setAttribute("tender", null);
    }

    /**
     * 投标前验证
     *
     * @param borrowModel  投标信息
     * @param tenderUser   投标用户信息
     * @param isExperience 是否体验标
     */
    private void checkTender(BorrowModel borrowModel, User tenderUser, boolean isExperience) {

        long userId = tenderUser.getUserId();

        UserCache userCache = UserUtils.getUserCacheByUserId(tenderUser);

        // 返回地址
        String redirectUrl = "/invest/" + borrowModel.getUuid() + "/detail.html";

        if (StringUtil.isBlank(borrowModel.getPayPwd())) {
            throw new BorrowException("交易密码不能为空!", redirectUrl);
        }

        if (!MD5.encode(borrowModel.getPayPwd()).equals(tenderUser.getPayPwd())) {
            throw new BorrowException("交易密码不正确!", redirectUrl);
        }

        // 借款人需处理完借款才能投标
        if (userCache.getUserType() == UserType.INVESTMENT_BORROWER && !borrowService.checkUserBorrowList(userId)) {
            throw new BorrowException("您还有未完成的借款!", redirectUrl);
        }

        if (userCache.getStatus() == UserCacheStatus.LOCK) {
            throw new BorrowException("您账号已经被锁定,不能进行投标!", redirectUrl);
        }

        if (borrowModel.getFixedTime() != null && DateUtil.getNow().before(borrowModel.getFixedTime())) {
            throw new BorrowException("还未开标,无法投标!", redirectUrl);
        }

        // 初审通过的标 才能投
        if (borrowModel.getStatus() != BorrowStatus.STATUS_TRIAL_PASSED) {
            throw new BorrowException("该标还未审批,不能进行投标!", redirectUrl);
        }

        if (borrowModel.getUser().getUserId() == userId) {
            throw new BorrowException("您不能投自己发布的标!", redirectUrl);
        }

        // 体验标校验
        if (isExperience) {
            // 体验券必须
            long[] experienceIds = borrowModel.getExperiences();
            if (experienceIds == null) {
                throw new BorrowException("投标失败,请选择一张体验券!", redirectUrl);
            }

            // 体验金金额校验
            if (experienceIds.length > 1) {
                throw new BorrowException("投标失败,只能使用一张体验券!", redirectUrl);
            }

            // 查询并设置体验金金额
            double totalExperienceMoney = experienceService.sumAmount(experienceIds, userId);
            borrowModel.setTotalExperienceMoney(totalExperienceMoney);
            if (totalExperienceMoney <= 0) {
                throw new BorrowException("投标失败,请正确使用体验券!", redirectUrl);
            }

            // 该体验券是否已经被使用
            if (!experienceService.checkExperience(experienceIds, tenderUser)) {
                throw new BusinessException("投标失败,该笔投标包含已被使用的体验券!", redirectUrl);
            }

            // 该体验标还款方式不正确
            if (borrowModel.getBorrowTimeType() != BorrowTimeType.DAY || borrowModel.getStyle() != BorrowStyle.STYLE_ONETIME_REPAYMENT) {
                throw new BorrowException("该体验标的还款方式设置错误!请联系管理员!", redirectUrl);
            }
        } else {
            AccountDao accountDao = (AccountDao) BeanUtil.getBean("accountDao");
            Account account = accountDao.findByUserId(tenderUser.getUserId());

            // 实际支付金额
            double actualTenderMoney = borrowModel.getMoney();
            if (actualTenderMoney <= 0) {
                throw new BorrowException("实际支付金额不能少于1元!", redirectUrl);
            }

            if (actualTenderMoney > account.getUseMoney()) {
                throw new BorrowException("您的可用余额不足!", redirectUrl);
            }

            double tenderTotalAmount = borrowModel.getAccount();// 标的总额
            double tenderYesAmount = borrowModel.getAccountYes();// 已投金额
            if (tenderYesAmount >= tenderTotalAmount) {
                throw new BorrowException("该标已满!", redirectUrl);
            }

            // 可投金额
            double canTenderAmount = BigDecimalUtil.sub(tenderTotalAmount, tenderYesAmount);
            // 投标金额不得大于 可投金额
            if (actualTenderMoney > canTenderAmount) {
                throw new BorrowException("已超标,请刷新页面,重新修改投资金额!", redirectUrl);
            }

            // 最小投标金额
            double tenderLowestAmount = borrowModel.getLowestAccount();
            // 可投金额 >= 最小投标额 校验最小投标金额
            if (canTenderAmount >= tenderLowestAmount && tenderLowestAmount > 0) {
                // 投标金额不得小于最小投标金额
                if (actualTenderMoney < tenderLowestAmount) {
                    throw new BorrowException(MessageFormat.format("投标金额不能小于单笔最小投标金额￥{0}元!", tenderLowestAmount), redirectUrl);
                }
            }

            //0元购的标所投金额需是最小金额的整数倍
            if(borrowModel.getType() == BorrowType.DELIVER_GOODS){
                if(actualTenderMoney%tenderLowestAmount>0){
                    throw new BorrowException(MessageFormat.format("该标投标金额需是最小投标金额￥{0}的整数倍!", tenderLowestAmount), redirectUrl);
                }
            }

  /*          // 第三方可用余额 大于 投标金额 不允许投标
            String tppUserCustId = UserUtils.getUserTppCustId(tenderUser.getUserId());
            QueryBalanceResponse queryBalanceResponse = sinaPayService.queryBalance(tppUserCustId);
            if (actualTenderMoney > queryBalanceResponse.getAvailableBalance()) {
                throw new BorrowException("您的托管资金还存在未处理记录,请耐心等待!", redirectUrl);
            }
*/
            // 加息券不能使用于一个月的标
            if (this.model.getRateInterestId() > 0 && BorrowTimeType.MONTH == borrowModel.getBorrowTimeType() && borrowModel.getTimeLimit() == 1) {
                throw new BorrowException("加息券不能使用于一个月的标!", redirectUrl);
            }

            // 单笔最大投标金额
            double mostSingleAccountNum = borrowModel.getMostSingleLimit();
            if (mostSingleAccountNum > 0 && actualTenderMoney > mostSingleAccountNum) {
                throw new BorrowException(MessageFormat.format("投标金额不能大于单笔最大投标总额￥{0}元!", mostSingleAccountNum), redirectUrl);
            }

            // 推荐标 及 0元购 不能使用红包及加息券
            if (borrowModel.getType() == BorrowType.DELIVER_GOODS || borrowModel.isRecommend() == true) {
                if (this.model.getRateInterestId() > 0) {
                    throw new BorrowException("该标种无法使用加息券!", redirectUrl);
                }
                if (borrowModel.getTotalRedEnvelopeMoney() > 0) {
                    throw new BorrowException("该标种无法使用红包!", redirectUrl);
                }
            }

            // 累积最大投标金额
            double mostTenderMoney = borrowModel.getMostAccount();
            if (mostTenderMoney > 0) {
                // 该用户已经投标的金额
                double hasTenderMoney = borrowTenderService.hasTenderTotalPerBorrowByUserid(borrowModel.getId(), tenderUser.getUserId());
                // 剩余可投金额（最大投标金额 - 已投金额）
                double remainderCanMostTenderMoney = mostTenderMoney - hasTenderMoney;
                if (remainderCanMostTenderMoney == 0) {
                    throw new BorrowException(MessageFormat.format("您对该标的投标金额已达到最大投标总额￥{0},无法继续投标!", mostTenderMoney), redirectUrl);
                }
                // 实际投标 > 剩余可投金额
                if (actualTenderMoney > remainderCanMostTenderMoney) {
                    throw new BorrowException(MessageFormat.format("您对该标的投标金额不能大于最大累积投标额,您当前还可以投￥{0}元", remainderCanMostTenderMoney), redirectUrl);
                }
            }

            // 红包使用规则校验
            String redPacketsUseRule = SystemConfigHelper.getValue(Nid.RED_PACKETS_RULE);
            if (SystemConfigHelper.getStatus(Nid.RED_PACKETS_RULE) == RedValidStatus.CAN_USE && !StringUtil.isBlank(redPacketsUseRule)) {// 规则是否启用
                double totalRedEnvelopeMoney = borrowModel.getTotalRedEnvelopeMoney();// 使用红包总额
                String redPacketsRuleList[] = redPacketsUseRule.split(",");
                for (int i = 0; i < redPacketsRuleList.length; i++) {
                    String redPacketsRules[] = redPacketsRuleList[i].split("\\^");
                    if (redPacketsRules.length < 3) {
                        throw new BorrowException("红包使用异常,请联系客服!", redirectUrl);
                    }
                    double canUseLowerLimit = Double.parseDouble(redPacketsRules[0]);
                    double canUseUpperLimit = Double.parseDouble(redPacketsRules[1]);
                    double canUseRedPacket = Double.parseDouble(redPacketsRules[2]);
                    if (canUseLowerLimit < actualTenderMoney && actualTenderMoney <= canUseUpperLimit) {
                        if (totalRedEnvelopeMoney > canUseRedPacket) {
                            throw new BorrowException(MessageFormat.format("您当前投标金额只能使用包含￥{0}元以下的红包！", canUseRedPacket), redirectUrl);
                        }
                    }
                    if (i == redPacketsRuleList.length - 1 && canUseUpperLimit < actualTenderMoney) {// 校验范围以外的情况,不能超出红包允许最大范围
                        if (totalRedEnvelopeMoney > canUseRedPacket) {
                            throw new BorrowException(MessageFormat.format("您当前投标金额只能使用包含￥{0}元以下的红包！", canUseRedPacket), redirectUrl);
                        }
                    }
                }
            }
        }
    }

    /**
     * 投标补单
     */
    @Action(value = NotifyUrl.RE_TENDER_REQ_URL)
    public void reTender() {
       /* String token = paramString("token");
        if (NotifyUrl.RE_CALL_TOKEN.equalsIgnoreCase(token)) {
            throw new BorrowException("令牌不正解无法操作!", BorrowException.TYPE_JSON);
        }
        long orderNo = paramLong("order_no");
        if (orderNo == 0) {
            throw new BorrowException("该队列不存在!", BorrowException.TYPE_JSON);
        }


        Gson gson = new Gson();
        BorrowModel model = gson.fromJson(queueLog.getParameter1(), BorrowModel.class);
        User tenderUser = gson.fromJson(queueLog.getParameter2(), User.class);
        reCheckTender(model, tenderUser, queueLog);
        // 投标参数取回
        putQueue(model, tenderUser, );*/
    }

    /**
     * 投标被单校验
     *
     * @param borrowModel 投标信息
     * @param tenderUser  投标用户信息
     * @param queueLog    队列Log
     */
    private void reCheckTender(BorrowModel borrowModel, User tenderUser, QueueLog queueLog) {

        if (queueLog == null) {
            throw new BorrowException("该队列不存在!", BorrowException.TYPE_JSON);
        }

        if (queueLog.getCategory() != QueueLogCategory.TENDER_CUSTOM_COLLECT) {
            throw new BorrowException("非投标业务,不能操作!", BorrowException.TYPE_JSON);
        }

        long userId = tenderUser.getUserId();

        AccountDao accountDao = (AccountDao) BeanUtil.getBean("accountDao");
        Account account = accountDao.findByUserId(tenderUser.getUserId());

        // 实际支付金额
        double actualTenderMoney = borrowModel.getMoney();
        if (actualTenderMoney > account.getUseMoney()) {
            throw new BorrowException("您的可用余额不足,投标失败!", BorrowException.TYPE_JSON);
        }

        double tenderTotalAmount = borrowModel.getAccount();// 标的总额
        double tenderYesAmount = borrowModel.getAccountYes();// 已投金额
        String tppUserCustId = UserUtils.getUserTppCustId(tenderUser.getUserId());
        if (tenderYesAmount == tenderTotalAmount) {

            throw new BorrowException(MessageFormat.format("已超标,需要退款给用户Id:{0} 新浪custId:{1} 订单号:{2}!", userId, tppUserCustId, queueLog.getOrderId()),
                    BorrowException.TYPE_JSON);
        }

        // 可投金额
        // 投标金额不得大于 可投金额
        double canTenderAmount = BigDecimalUtil.sub(tenderTotalAmount, tenderYesAmount);
        if (actualTenderMoney > canTenderAmount) {
            throw new BorrowException(MessageFormat.format("已超标,需要退款给用户Id:{0} 新浪custId:{1} 订单号:{2}!", userId, tppUserCustId, queueLog.getOrderId()), BorrowException.TYPE_JSON);
        }

        // 第三方可用余额 大于 投标金额 不允许投标
        sinaQueryBalanceResponse queryBalanceResponse = sinaPayService.queryBalance(tppUserCustId);
        if (actualTenderMoney > queryBalanceResponse.getAvailableBalance()) {
            throw new BorrowException("您的托管资金还存在未处理记录,请耐心等待!", BorrowException.TYPE_JSON);
        }
    }

    private void putQueue(BorrowModel model, User tenderUser) {
        // 投标放入队列中
        BorrowValueEvent event = new BorrowValueEvent();
        event.setBorrowModel(model);
        event.setTaskProcessorClass(TenderTaskProcessor.class);
        event.setResultFlag(model.getTenderResultFlg());
        event.setUser(tenderUser);
        event.setClientIp(Global.getIP());
        //将事件放入到队列中
        QueueHandlers.put(event);
    }

    /**
     * 抵押物图片
     *
     * @throws Exception if has error
     */
    @Action("/invest/getMortgagePics")
    public void getMortgagePics() throws Exception {
        long id = paramLong("id");
        long type = paramLong("type");
        List<BorrowUpload> list = borrowUploadService.findByMortgageIdAndType(id, type);

        retMap = new HashMap<String, Object>();
        retMap.put("list", list);
        printWebJson(getStringOfJpaObj(retMap));
    }

    /**
     * 资产包更新记录
     *
     * @throws Exception if has error
     */
    @Action("/invest/getMortgageRecord")
    public void getMortgageRecord() throws Exception {
        Map retMap = new HashMap<String, Object>();
        long id = paramLong("id");
        Borrow borrow = borrowService.find(id);
        retMap.put("account", borrow.getAccount());
        List<BorrowMortgage> initList = borrowMortgageService.findByBorrowIdAndNum(id, 0);
        retMap.put("initList", initList);
        Object[] initTotalPrice = borrowMortgageService.getTotalPriceByBorrowIdAndNum(id, 0);
        retMap.put("initTotalAssessPrice", initTotalPrice[0]);
        retMap.put("initTotalMortgagePrice", initTotalPrice[1]);
        int num = borrowMortgageService.getMaxNumByBorrowId(id);
        double totalAssessPrice = (Double) initTotalPrice[0];
        double totalMortgagePrice = (Double) initTotalPrice[1];
        List<BorrowMortgageModel> list = new ArrayList<BorrowMortgageModel>();
        for (int i = 1; i < num + 1; i++) {
            List<BorrowMortgage> inList = borrowMortgageService.findInByBorrowIdAndNum(id, i);
            BorrowMortgageModel bmm = new BorrowMortgageModel();
            double inTotalAssessPrice = 0;
            double inTotalMortgagePrice = 0;
            for (BorrowMortgage bm : inList) {
                inTotalAssessPrice = BigDecimalUtil.add(inTotalAssessPrice, bm.getAssessPrice());
                inTotalMortgagePrice = BigDecimalUtil.add(inTotalMortgagePrice, bm.getMortgagePrice());
            }
            List<BorrowMortgage> outList = borrowMortgageService.findByBorrowIdAndNumAndStatus(id, i, 2);
            double outTotalAssessPrice = 0;
            double outTotalMortgagePrice = 0;
            for (BorrowMortgage bm : outList) {
                outTotalAssessPrice = BigDecimalUtil.add(outTotalAssessPrice, bm.getAssessPrice());
                outTotalMortgagePrice = BigDecimalUtil.add(outTotalMortgagePrice, bm.getMortgagePrice());
            }
            totalAssessPrice = BigDecimalUtil.add(totalAssessPrice, inTotalAssessPrice, -outTotalAssessPrice);
            totalMortgagePrice = BigDecimalUtil.add(totalMortgagePrice, inTotalMortgagePrice, -outTotalMortgagePrice);
            bmm.setInTotalAssessPrice(inTotalAssessPrice);
            bmm.setInTotalMortgagePrice(inTotalMortgagePrice);
            bmm.setOutTotalAssessPrice(outTotalAssessPrice);
            bmm.setOutTotalMortgagePrice(outTotalMortgagePrice);
            bmm.setTotalAssessPrice(totalAssessPrice);
            bmm.setTotalMortgagePrice(totalMortgagePrice);
            bmm.setUpdateTime(inList.get(0).getAddTime());
            bmm.setInList(inList);
            bmm.setOutList(outList);
            list.add(bmm);
        }
        retMap.put("list", list);
        printWebJson(getStringOfJpaObj(retMap));
    }

    /**
     * 用户实物照
     *
     * @throws Exception if has error
     */
    @Action("/invest/getUserUpload")
    public void getUserUpload() throws Exception {
        long id = paramLong("id");
        Borrow borrow = borrowService.find(id);
        User user = borrow.getUser();
        List<UserUpload> list = userUploadService.findByUser(user);

        Map retMap = new HashMap<String, Object>();
        retMap.put("list", list);
        printWebJson(getStringOfJpaObj(retMap));
    }

    /**
     * 协议预览
     *
     * @throws Exception if has error
     */
    @Action("/invest/protocolPreview")
    public String protocolPreview() throws Exception {
        long id = paramLong("id");
        Borrow borrow = borrowService.find(id);
        User borrowUser = borrow.getUser();
        request.setAttribute("borrow", borrow);
        request.setAttribute("borrowUser", borrowUser);
        request.setAttribute("userCache", UserUtils.getUserCacheByUserId(borrowUser));

        VerifyLog verifyLog = verifyLogService.findByType(id, "borrow", 1);
        request.setAttribute("verifyTime", verifyLog.getTime());
        request.setAttribute("bigMoney", MoneyUtil.convert(borrow.getAccount() + ""));
        String repayStyle = "";
        switch (borrow.getStyle()) {
            case BorrowStyle.STYLE_MONTHLY_INTEREST:
                repayStyle = "每月还息到期还本";
                break;
            case BorrowStyle.STYLE_ONETIME_REPAYMENT:
                repayStyle = "按月分期付款";
                break;
        }
        request.setAttribute("repayStyle", repayStyle);
        List<BorrowRepayment> list = borrowRepaymentService.getRepaymentByBorrowId(id);
        request.setAttribute("list", list);
        return "protocolPreview";
    }

    /**
     * 趣影计划页面
     *
     * @return
     * @throws Exception
     */
    @Action(value = "/invest/filmIndex", results = {@Result(name = "filmIndex", type = "ftl", location = "/invest/filmIndex.html")})
    public String filmIndex() throws Exception {
        request.setAttribute("nid", "filmIndex");
        return "filmIndex";
    }

    /**
     * 趣影计划详细页面
     *
     * @return
     * @throws Exception
     */
    @Action(value = "/invest/103detail", results = {@Result(name = "103detail", type = "ftl", location = "/invest/103detail.html")})
    public String filmDetail() throws Exception {
        request.setAttribute("nid", "103detail");
        return "103detail";
    }

    /**
     * 趣影计划商城页面
     *
     * @return
     * @throws Exception
     */
    @Action(value = "/invest/filmShop", results = {@Result(name = "filmShop", type = "ftl", location = "/invest/filmShop.html")})
    public String filmShop() throws Exception {
        request.setAttribute("nid", "filmShop");
        return "filmShop";
    }

    /**
     * 趣影计划商城页面
     *
     * @return
     * @throws Exception
     */
    @Action(value = "/invest/enjoyIndex")
    public String enjoyIndex() throws Exception {
        request.setAttribute("nid", "enjoyIndex");
        return "enjoyIndex";
    }

    /**
     * 奖项查询跳转
     */
    @Action(value = "/invest/award", interceptorRefs = {@InterceptorRef("session"), @InterceptorRef("globalStack")})
    public String award() throws Exception {
        String uuid = request.getParameter("uuid");
        String borrowName = borrowService.find(uuid).getName();
        request.setAttribute("borrowName", borrowName);
        return "award";
    }

    /**
     * 该标第一个投标用户
     */
    @Action(value = "/invest/firstTender", interceptorRefs = {@InterceptorRef("session"), @InterceptorRef("globalStack")})
    public void firstTender() throws Exception {
        String uuid = paramString("uuid");
        long borrowId = borrowService.find(uuid).getId();
        AwardModel firstTender = (AwardModel) context.getAttribute("firstTender" + uuid);
        if (StringUtil.isBlank(firstTender)) {
            firstTender = awardSearchService.firstTender(borrowId);
            context.setAttribute("firstAward" + uuid, firstTender);
        }

        retMap = new HashMap<String, Object>();
        retMap.put("firstTender", firstTender);
        printWebJson(getStringOfJpaObj(retMap));
    }

    /**
     * 该标最后一个投标用户
     */
    @Action(value = "/invest/lastTender", interceptorRefs = {@InterceptorRef("session"), @InterceptorRef("globalStack")})
    public void lastTender() throws Exception {
        String uuid = paramString("uuid");
        long borrowId = borrowService.find(uuid).getId();
        AwardModel lastTender = (AwardModel) context.getAttribute("lastTender" + uuid);
        if (StringUtil.isBlank(lastTender)) {
            lastTender = awardSearchService.lastTender(borrowId);
            context.setAttribute("lastTender" + uuid, lastTender);
        }

        retMap = new HashMap<String, Object>();
        retMap.put("lastTender", lastTender);
        printWebJson(getStringOfJpaObj(retMap));
    }

    /**
     * 该标投资最多投标用户
     */
    @Action(value = "/invest/mostTender", interceptorRefs = {@InterceptorRef("session"), @InterceptorRef("globalStack")})
    public void mostTender() throws Exception {
        String uuid = paramString("uuid");
        long borrowId = borrowService.find(uuid).getId();
        AwardModel mostTender = (AwardModel) context.getAttribute("mostTender" + uuid);
        if (StringUtil.isBlank(mostTender)) {
            mostTender = awardSearchService.mostTender(borrowId);
            context.setAttribute("mostTender" + uuid, mostTender);
        }

        retMap = new HashMap<String, Object>();
        retMap.put("mostTender", mostTender);
        printWebJson(getStringOfJpaObj(retMap));
    }

    /**
     * 所有标第一个投标用户
     */
    @Action(value = "/invest/allFirstTender", interceptorRefs = {@InterceptorRef("session"), @InterceptorRef("globalStack")})
    public void allFirstTender() throws Exception {
        List<AwardModel> allFirstTender = awardSearchService.allFirstTender();

        retMap = new HashMap<String, Object>();
        retMap.put("allFirstTender", allFirstTender);
        printWebJson(getStringOfJpaObj(retMap));
    }

    /**
     * 所有标最后一个投标用户
     */
    @Action(value = "/invest/allLastTender", interceptorRefs = {@InterceptorRef("session"), @InterceptorRef("globalStack")})
    public void allLastTender() throws Exception {
        List<AwardModel> allLastTender = awardSearchService.allLastTender();

        retMap = new HashMap<String, Object>();
        retMap.put("allLastTender", allLastTender);
        printWebJson(getStringOfJpaObj(retMap));
    }

    /**
     * 所有标投资最多投标用户
     */
    @Action(value = "/invest/allMostTender", interceptorRefs = {@InterceptorRef("session"), @InterceptorRef("globalStack")})
    public void allMostTender() throws Exception {
        List<AwardModel> allMostTender = awardSearchService.allMostTender();

        retMap = new HashMap<String, Object>();
        retMap.put("allMostTender", allMostTender);
        printWebJson(getStringOfJpaObj(retMap));
    }

    /**
     * 新浪存钱罐年利率
     *
     * @throws Exception
     */
    @Action("/invest/sinaApr")
    public void sinaApr() throws Exception {

        String yieldList = SystemConfigHelper.getValue(Nid.YIELD_LIST);
        if (StringUtil.isEmpty(yieldList)) return;

        String[] ary = yieldList.split("\\|");
        List<String> day = new ArrayList<String>();
        List<String> apr = new ArrayList<String>();
        for (int i = 0; i < 7; i++) {
            String[] arr = ary[6 - i].toString().split("\\^");
            day.add(ary[6 - i].substring(0, 4) + "-" + ary[6 - i].substring(4, 6) + "-" + ary[6 - i].substring(6, 8));
            apr.add(arr[1]);
        }

        retMap = new HashMap<String, Object>();
        retMap.put("day", day.toArray());
        retMap.put("apr", apr.toArray());
        retMap.put("yApr", apr.get(6));
        printWebJson(getStringOfJpaObj(retMap));
    }
}
